package com.company.project.common.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.JSON;
import com.company.project.common.exception.BusinessException;
import com.company.project.vo.req.ApiData;
import com.company.project.vo.resp.ReceiveResult;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * 密码加密
 *
 * @author
 * @version V1.0
 * @date 2020年3月18日
 */
public class PasswordEncoder {

    private static Logger logger = LoggerFactory.getLogger(PasswordEncoder.class);

    @Value("${dcicurl}")
    private String url;

    private final static String[] HEX_DIGITS = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d",
            "e", "f"};

    private final static String MD5 = "MD5";

    private Object salt;
    private String algorithm;
    
    public PasswordEncoder() {        
    }

    public PasswordEncoder(Object salt) {
        this(salt, MD5);
    }

    public PasswordEncoder(Object salt, String algorithm) {
        this.salt = salt;
        this.algorithm = algorithm;
    }

    /**
     * 密码加密
     *
     * @param rawPass 密码
     * @return 加密后
     */
    public String encode(String rawPass) {
        String result = null;
        try {
            MessageDigest md = MessageDigest.getInstance(algorithm);
            // 加密后的字符串
            result = byteArrayToHexString(md.digest(mergePasswordAndSalt(rawPass).getBytes(StandardCharsets.UTF_8)));
        } catch (Exception e) {
            logger.error(e.toString(), e);
        }
        return result;
    }
    
    /**
	 * 
	 * @Des：根据姓名和身份证号码生成MD5（身份证号最后一位若是x，转为大写X），
	 * 		在数字中国创新赛平台上判断是否已注册
	 * @param name
	 * @param idNumber
	 * @return
	 */
	@SuppressWarnings("deprecation")
	public boolean isRegistered(String name,String idNumber,String url) {
		boolean result = false;
		// 加密后的字符串
		String dcic_user_id = getMD5(name, idNumber);	
		String app_id = "d18xm8uuiwe5315l";
		String app_secret = "4qwd9di6rs4xew0p3ejv8aa97i0it8j5";
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		String date = sdf.format(localToUTC());
		SimpleDateFormat sdf2 = new SimpleDateFormat("HH:mm:ss");
		String time = sdf2.format(localToUTC());
		String timestamp = date+"T"+time+"Z";
		String urlEncodertimestamp= URLEncoder.encode(timestamp);
		String sign_string = "app_id="+app_id+"&dcic_user_id="+dcic_user_id+"&method=POST&path=%2Fopen%2Fapi%2Fuser%2Fverify&timestamp="+urlEncodertimestamp;
		
		String sign = getSHA256(app_secret + " " + sign_string);
		ApiData data = new ApiData(app_id, dcic_user_id, timestamp, sign);
		// 调用远程接口验证
		result = valid(data,url); 
		return result;	
	}
	
	/**
     * <p>Description: 本地时间转化为UTC时间</p>
     * @param 
     * @return
     * @author  
     * @date  2018年10月19日 下午2:23:43
     */
    public Date localToUTC() {
        long localTimeInMillis=new Date().getTime();
        /** long时间转换成Calendar */
        Calendar calendar= Calendar.getInstance();
        calendar.setTimeInMillis(localTimeInMillis);
        /** 取得时间偏移量 */
        int zoneOffset = calendar.get(java.util.Calendar.ZONE_OFFSET);
        /** 取得夏令时差 */
        int dstOffset = calendar.get(java.util.Calendar.DST_OFFSET);
        /** 从本地时间里扣除这些差量，即可以取得UTC时间*/
        calendar.add(java.util.Calendar.MILLISECOND, -(zoneOffset + dstOffset));
        /** 取得的时间就是UTC标准时间 */
        Date utcDate=new Date(calendar.getTimeInMillis());
        return utcDate;
    }
	
	public static void main(String[] args) {
		PasswordEncoder encoder = new PasswordEncoder();
		////encoder.isRegistered("王彬福", "350822199402280010");	
		encoder.isRegistered("李松", "420983199309179037","https://dcic-dev.datafountain.cn/open/api/user/verify");
    }
	
	/**
	 * @Des：远程验证
	 * @param data
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public boolean valid(ApiData data,String url) {
		RestTemplate resttemplate = new RestTemplate();
		// 设置请求头
		HttpHeaders headers = new HttpHeaders();
		MediaType headerType = MediaType.parseMediaType("application/json");
		headers.setContentType(headerType);
		// 创建json对象，保存需要发送的内容，然后将json对象转为字符串再写到链接的输出流
		HttpEntity request = new HttpEntity(JSON.toJSONString(data), headers);
		//String url = "https://dcic-dev.datafountain.cn/open/api/user/verify";
		//String url = "https://dcic.datafountain.cn/open/api/user/verify";	
		 
		ResponseEntity<String> response = resttemplate.postForEntity(url, request, String.class);			
		try {
			ReceiveResult result = JSON.parseObject(response.getBody(), ReceiveResult.class);
			logger.info("验证用户注册信息：" + JSON.toJSONString(result));
			if(result.getMessage().equals("success")) {
				return true;
			}
		} catch (Exception e) {						
			logger.error("验证用户注册信息失败");
			logger.error(e.getMessage());
			throw new BusinessException("服务异常，请稍后操作!");
		}
		return false;
	}
	
	public String getMD5(String name,String idNumber) {
		String result = null;
        try {
            MessageDigest md = MessageDigest.getInstance(MD5);
            String str = name.toUpperCase()+idNumber.toUpperCase();
            // 加密后的字符串
            md.update(str.getBytes("UTF-8"));
            result = byteArrayToHexString(md.digest());           
        } catch (Exception e) {
            logger.error(e.toString(), e);
        }
		return result;	
	}
	
	/**
	 * 利用java原生的类实现SHA256加密
	 * 
	 * @param str 加密后的报文
	 * @return
	 */
	public String getSHA256(String str) {
		MessageDigest messageDigest;
		String encodestr = "";
		try {
			messageDigest = MessageDigest.getInstance("SHA-256");
			messageDigest.update(str.getBytes("UTF-8"));
			encodestr = byteArrayToHexString(messageDigest.digest());
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return encodestr;
	}

    /**
     * 密码匹配验证
     *
     * @param encPass 密文
     * @param rawPass 明文
     * @return 是否匹配
     */
    public boolean matches(String encPass, String rawPass) {
        String pass1 = "" + encPass;
        String pass2 = encode(rawPass);

        return pass1.equals(pass2);
    }

    private String mergePasswordAndSalt(String password) {
        if (password == null) {
            password = "";
        }

        if ((salt == null) || "".equals(salt)) {
            return password;
        } else {
            return password + "{" + salt.toString() + "}";
        }
    }

    /**
     * 转换字节数组为16进制字串
     *
     * @param b 字节数组
     * @return 16进制字串
     */
    private String byteArrayToHexString(byte[] b) {
        StringBuilder resultSb = new StringBuilder();
        for (byte value : b) {
            resultSb.append(byteToHexString(value));
        }
        return resultSb.toString();
    }

    /**
     * 将字节转换为16进制
     *
     * @param b 字节
     * @return 16进制
     */
    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0) {
            n = 256 + n;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return HEX_DIGITS[d1] + HEX_DIGITS[d2];
    }

}